#IT326 Project
Description of the dataset:
This dataset, obtained from vgchartz.com, provides a valuable
resource for exploring the dynamics between gaming platforms and genres
in the top 100 global video games. It enables us to analyze the
platforms that are influencing worldwide sales, identify the most
prosperous genres in various global regions, and track the evolving
trends in both platform preference and genre popularity over time.
Our goal:
Our goal from studying this dataset is to utilize classification and
clustering techniques on the input data to make predictions about the
popularity of upcoming games.
Attributes description:
| Rank |
Ranking of the game based on global sales. |
Numeric |
| Name |
Name of the game. |
Nominal |
| Platform |
Platform the game was released on. |
Nominal |
| Year |
Year the game was released. |
Ordinal |
| Genre |
Genre of the game |
Nominal |
| Publisher |
Publisher of the game. |
Nominal |
| NA_Sales |
Sales of the game in North America |
Numeric (ratio-scaled) |
| EU_Sales |
Sales of the game in Europe |
Numeric (ratio-scaled) |
| JP_Sales |
Sales of the game in Japan |
Numeric (ratio-scaled) |
| Other_Sales |
Sales of the game in other regions |
Numeric (ratio-scaled) |
| Global_Sales |
Total sales of the game worldwide |
Numeric (ratio-scaled) |
Class label:
Popular’ is our class label, we will use Global_Sales attribute to
predict whether a game will sell 1000000 or more globally. Our task of
data mining is regression.
Importing our dataset:
dataset=read.csv("vgsales.csv")
loading libraries needed for our data mining tasks:
library(outliers)
library(dplyr)
library(Hmisc)
library(ggplot2)
library(cowplot)
library(mlbench)
library(caret)
library(faux)
library(DataExplorer)
library(randomForest)
options(max.print=9999999)
General info about our dataset including number of rows and columns,
and cheking dimensionality and coulumns names:
nrow(dataset)
ncol(dataset)
dim(dataset)
names(dataset)
<<<<<<< HEAD
[1] 16598
ncol(dataset)
[1] 11
dim(dataset)
[1] 16598 11
names(dataset)
[1] "Rank" "Name" "Platform" "Year" "Genre" "Publisher" "NA_Sales" "EU_Sales" "JP_Sales" "Other_Sales"
[11] "Global_Sales"
=======
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
Dataset structure including number of coulums and rows, attribute
types:
str(dataset)
sample of raw dataset(first 10 rows):
head(dataset, 10)
<<<<<<< HEAD
=======
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
sample of raw dataset(last 10 rows):
tail(dataset, 10)
<<<<<<< HEAD
=======
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
summary of our dataset:
summary(dataset)
<<<<<<< HEAD
Rank Name Platform Year Genre Publisher NA_Sales EU_Sales
Min. : 1 Length:16598 Length:16598 Length:16598 Length:16598 Length:16598 Min. : 0.0000 Min. : 0.0000
1st Qu.: 4151 Class :character Class :character Class :character Class :character Class :character 1st Qu.: 0.0000 1st Qu.: 0.0000
Median : 8300 Mode :character Mode :character Mode :character Mode :character Mode :character Median : 0.0800 Median : 0.0200
Mean : 8301 Mean : 0.2647 Mean : 0.1467
3rd Qu.:12450 3rd Qu.: 0.2400 3rd Qu.: 0.1100
Max. :16600 Max. :41.4900 Max. :29.0200
JP_Sales Other_Sales Global_Sales
Min. : 0.00000 Min. : 0.00000 Min. : 0.0100
1st Qu.: 0.00000 1st Qu.: 0.00000 1st Qu.: 0.0600
Median : 0.00000 Median : 0.01000 Median : 0.1700
Mean : 0.07778 Mean : 0.04806 Mean : 0.5374
3rd Qu.: 0.04000 3rd Qu.: 0.04000 3rd Qu.: 0.4700
Max. :10.22000 Max. :10.57000 Max. :82.7400
=======
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
variance of numeric data:
var(dataset$NA_Sales)
var(dataset$EU_Sales)
var(dataset$JP_Sales)
var(dataset$Other_Sales)
var(dataset$Global_Sales)
Graphs:
dataset2 <- dataset %>% sample_n(50)
tab <- dataset2$Platform %>% table()
precentages <- tab %>% prop.table() %>% round(3) * 100
txt <- paste0(names(tab), '\n', precentages, '%')
pie(tab, labels=txt , main = "Pie chart of Platform")
<<<<<<< HEAD

=======
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
We notice from the pie chart of platform attribute that releasing a
game for PS users will increase the popularity of the game since it is
the most common platform among gamers.
# coloring barplot and adding text
tab<-dataset$Genre %>% table()
precentages<-tab %>% prop.table() %>% round(3)*100
txt<-paste0(names(tab), '\n',precentages,'%')
bb <- dataset$Genre %>% table() %>% barplot(axisnames=F, main = "Barplot for Popular genres ",ylab='count',col=c('pink','blue','lightblue','green','lightgreen','red','orange','red','grey','yellow','azure','olivedrab'))
text(bb,tab/2,labels=txt,cex=1.5)
<<<<<<< HEAD

=======
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
In terms of genre, action games are the most popular, followed by
sports and music games. It is safe to assume that a high number of
genres of this nature exist due to their popularity and sales.
boxplot(dataset$NA_Sales , main="
BoxPlot for NA_Sales")
<<<<<<< HEAD

=======
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
boxplot(dataset$EU_Sales, main="
BoxPlot for EU_Sales")
<<<<<<< HEAD

=======
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
boxplot(dataset$JP_Sales , main="
BoxPlot for JP_Sales")
<<<<<<< HEAD

=======
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
boxplot(dataset$Other_Sales , main="
BoxPlot for Other_Sales")
<<<<<<< HEAD

=======
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
The boxplot of the Other-sales attribute indicate that the values are
close to each other ,and there is a lot of outliers since the dataset
represents the global sales of video games.
boxplot(dataset$Global_Sales , main="BoxPlot for Global_Sales")
<<<<<<< HEAD

=======
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
The boxplot of the Global-sales attribute indicate that the values
are close to each other ,and there is a lot of outliers since the
dataset represents the global sales of video games.
qplot(data = dataset, x=Global_Sales,y=Genre,fill=I("yellow"),width=0.5 ,geom = "boxplot" , main = "BoxPlots for genre and Global_Sales")
<<<<<<< HEAD
Warning: `qplot()` was deprecated in ggplot2 3.4.0.

=======
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
dataset$Year %>% table() %>% barplot( main = "Barplot for year")
<<<<<<< HEAD

=======
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
pairs(~NA_Sales + EU_Sales + JP_Sales + Other_Sales + Global_Sales, data = dataset,
main = "Sales Scatterplot")
<<<<<<< HEAD

=======
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
We used Scatterplot to determine the type of correlation we have
between the sales; we can see that the majority have positive
correlation with each other.
Pre - processing
Null checking
sum(is.na(dataset$Rank))
NullRank<-dataset[dataset$Rank=="N/A",]
NullRank
<<<<<<< HEAD
=======
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
checking for nulls in Rank (there is no nulls)
sum(is.na(dataset$Name))
[1] 0
NullName<-dataset[dataset$Name=="N/A",]
NullName
checking for nulls in name (there is no nulls)
sum(is.na(dataset$Platform))
NullPlatform<-dataset[dataset$Platform=="N/A",]
checking for nulls in Platform(there is no nulls)
<<<<<<< HEAD
sum(is.na(dataset$Year))
[1] 0
NullYear<-dataset[dataset$Year=="N/A",]
NullYear
=======
sum(is.na(dataset$Year))
NullYear<-dataset[dataset$Year=="N/A",]
NullYear
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
checking for nulls in year we won’t delete the null and we will leave
them as global constant because we want the sales data out of them.
sum(is.na(dataset$Genre))
NullGenre<-dataset[dataset$Genre=="N/A",]
NullGenre
<<<<<<< HEAD
=======
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
checking for nulls in Genre(there is no nulls)
sum(is.na(dataset$Publisher))
NullPublisher<-dataset[dataset$Publisher=="N/A",]
NullPublisher
<<<<<<< HEAD
=======
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
checking for nulls in Publisher. we won’t delete the null and we will
leave them as global constant as it is because we want the sales data of
them.
sum(is.na(dataset$Other_Sales))
NullOther_Sales<-dataset[dataset$Other_Sales=="N/A",]
There is no null values in the other_sales.
sum(is.na(dataset$Global_Sales))
NullGlobal_Sales<-dataset[dataset$Global_Saless=="N/A",]
There is no null values in the Global_Sales.
Encoding
dataset$Platform=factor(dataset$Platform,levels=c("2600","3DO","3DS","DC","DS","GB","GBA","GC","GEN","GG","N64","NES","NG","PC","PCFX","PS","PS2","PS3","PS4","PSP","PSV","SAT","SCD","SNES","TG16","Wii","WiiU","WS","X360","XB","XOne"), labels=c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31))
Since most machine learning algorithms work with numbers and not with
text or categorical variables, this column will be encoded to facilitate
our data mining task.
dataset$Genre=factor(dataset$Genre,levels=c("Action","Adventure","Fighting","Platform","Puzzle","Racing","Role-Playing","Shooter","Simulation","Sports","Strategy","Misc"),labels=c(1,2,3,4,5,6,7,8,9,10,11,12))
Since most machine learning algorithms work with numbers and not with
text or categorical variables, this column will be encoded to facilitate
our data mining task.
Outliers
outlier of NA_Sales
OutNA_Sales = outlier(dataset$NA_Sales, logical =TRUE)
sum(OutNA_Sales)
Find_outlier = which(OutNA_Sales ==TRUE, arr.ind = TRUE)
OutNA_Sales
Find_outlier
outlier of EU_Sales
OutEU_Sales = outlier(dataset$EU_Sales, logical =TRUE)
sum(OutEU_Sales)
Find_outlier = which(OutEU_Sales ==TRUE, arr.ind = TRUE)
OutEU_Sales
Find_outlier
outlier of JP_Sales
OutJP_Sales = outlier(dataset$JP_Sales, logical =TRUE)
sum(OutJP_Sales)
Find_outlier = which(OutJP_Sales ==TRUE, arr.ind = TRUE)
OutJP_Sales
Find_outlier
outlier of other_sales
OutOS=outlier(dataset$Other_Sales, logical=TRUE)
sum(OutOS)
Find_outlier=which(OutOS==TRUE, arr.ind=TRUE)
OutOS
Find_outlier
outlier of Global_sales
OutGS=outlier(dataset$Global_Sales, logical=TRUE)
sum(OutGS)
Find_outlier=which(OutGS==TRUE, arr.ind=TRUE)
OutGS
Find_outlier
Remove outliers
dataset= dataset[-Find_outlier,]
Normalization
Dataset before normalization:
datsetWithoutNormalization<-dataset
normalize <- function(x) {return ((x - min(x)) / (max(x) - min(x)))}
dataset$NA_Sales<-normalize(datsetWithoutNormalization$NA_Sales)
dataset$EU_Sales<-normalize(datsetWithoutNormalization$EU_Sales)
dataset$JP_Sales<-normalize(datsetWithoutNormalization$JP_Sales)
dataset$Other_Sales<-normalize(datsetWithoutNormalization$Other_Sales)
dataset$Global_Sales<-normalize(datsetWithoutNormalization$Global_Sales)
We chose min-max normalization instead of z-score normalization
because min-max transform the data into a specific range, which enhances
its suitability for visualization and comparison. Additionally, it
simplifies the process of assessing attribute importance and their
contributions to the model.
Feautre selection
Our class label (popular) refers to Global_Sales. Other sales regions
will be evaluated based on their importance to (global_sales) column.
and those that are less important will be deleted from the dataset. use
roc_curve area as score
roc_imp <- filterVarImp(x = dataset[,7:10], y = dataset$Global_Sales)
sort the score in decreasing order
roc_imp <- data.frame(cbind(variable = rownames(roc_imp), score = roc_imp[,1]))
roc_imp$score <- as.double(roc_imp$score)
roc_imp[order(roc_imp$score,decreasing = TRUE),]
<<<<<<< HEAD
=======
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
we will remove the (JP_Sales) because it is of low importance to our
class_label(Global_Sales)
dataset<- dataset[,-9]
Dataset after pre-processing
print(dataset)
<<<<<<< HEAD
=======
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f
<<<<<<< HEAD
LS0tCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KI0lUMzI2IFByb2plY3QKCgoKCiMgRGVzY3JpcHRpb24gb2YgdGhlIGRhdGFzZXQ6CgpUaGlzIGRhdGFzZXQsIG9idGFpbmVkIGZyb20gdmdjaGFydHouY29tLCBwcm92aWRlcyBhIHZhbHVhYmxlIHJlc291cmNlIGZvciBleHBsb3JpbmcgdGhlIGR5bmFtaWNzIGJldHdlZW4gZ2FtaW5nIHBsYXRmb3JtcyBhbmQgZ2VucmVzIGluIHRoZSB0b3AgMTAwIGdsb2JhbCB2aWRlbyBnYW1lcy4gSXQgZW5hYmxlcyB1cyB0byBhbmFseXplIHRoZSBwbGF0Zm9ybXMgdGhhdCBhcmUgaW5mbHVlbmNpbmcgd29ybGR3aWRlIHNhbGVzLCBpZGVudGlmeSB0aGUgbW9zdCBwcm9zcGVyb3VzIGdlbnJlcyBpbiB2YXJpb3VzIGdsb2JhbCByZWdpb25zLCBhbmQgdHJhY2sgdGhlIGV2b2x2aW5nIHRyZW5kcyBpbiBib3RoIHBsYXRmb3JtIHByZWZlcmVuY2UgYW5kIGdlbnJlIHBvcHVsYXJpdHkgb3ZlciB0aW1lLiAKCiMgU291cmNlIGFuZCBsaW5rOgpTb3VyY2U6IEthZ2dsZQoKVVJMIGxpbms6IGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvZ3JlZ29ydXQvdmlkZW9nYW1lc2FsZXMKCiMgT3VyIGdvYWw6CgpPdXIgZ29hbCAgZnJvbSBzdHVkeWluZyB0aGlzIGRhdGFzZXQgaXMgdG8gdXRpbGl6ZSBjbGFzc2lmaWNhdGlvbiBhbmQgY2x1c3RlcmluZyB0ZWNobmlxdWVzIG9uIHRoZSBpbnB1dCBkYXRhIHRvIG1ha2UgcHJlZGljdGlvbnMgYWJvdXQgdGhlIHBvcHVsYXJpdHkgb2YgdXBjb21pbmcgZ2FtZXMuCgoKCiMgQXR0cmlidXRlcyBkZXNjcmlwdGlvbjoKCgp8ICoqQXR0cmlidXRlcyBuYW1lKiogfCAqKkRlc2NyaXB0aW9uKiogICAgICAgICAgICAgICAgICAgfCAqKkRhdGEgdHlwZSoqIHwgCnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLXwKfFJhbmsgICAgICAgICAgICAgICB8IFJhbmtpbmcgb2YgdGhlIGdhbWUgYmFzZWQgb24gZ2xvYmFsIHNhbGVzLiB8IE51bWVyaWMgICAgICAgfAp8IE5hbWUgICAgICAgICAgICB8IE5hbWUgb2YgdGhlIGdhbWUuIHwgTm9taW5hbCAgICAgICB8IAp8IFBsYXRmb3JtICAgICAgfCBQbGF0Zm9ybSB0aGUgZ2FtZSB3YXMgcmVsZWFzZWQgb24uIHwgTm9taW5hbCAgICAgICB8IAp8IFllYXIgICAgICAgICAgICAgICB8IFllYXIgdGhlIGdhbWUgd2FzIHJlbGVhc2VkLiB8IE9yZGluYWwgICAgICAgfCAKfCBHZW5yZSAgICAgICAgICAgIHwgR2VucmUgb2YgdGhlIGdhbWUgfCBOb21pbmFsICAgICAgIHwgCnwgUHVibGlzaGVyICAgICAgfCBQdWJsaXNoZXIgb2YgdGhlIGdhbWUuIHwgTm9taW5hbCAgICAgICB8IAp8IE5BX1NhbGVzICAgICAgfCBTYWxlcyBvZiB0aGUgZ2FtZSBpbiBOb3J0aCBBbWVyaWNhIHwgTnVtZXJpYyAocmF0aW8tc2NhbGVkKSAgICAgICB8IAp8IEVVX1NhbGVzICAgICAgIHwgU2FsZXMgb2YgdGhlIGdhbWUgaW4gRXVyb3BlIHwgTnVtZXJpYyAocmF0aW8tc2NhbGVkKSAgICAgICAgfCAKfCBKUF9TYWxlcyAgICAgICAgfCBTYWxlcyBvZiB0aGUgZ2FtZSBpbiBKYXBhbiB8IE51bWVyaWMgKHJhdGlvLXNjYWxlZCkgICAgICAgIHwgCnwgT3RoZXJfU2FsZXMgfCBTYWxlcyBvZiB0aGUgZ2FtZSBpbiBvdGhlciByZWdpb25zIHwgTnVtZXJpYyAocmF0aW8tc2NhbGVkKSAgICAgICAgfCAKfCBHbG9iYWxfU2FsZXMgIHwgVG90YWwgc2FsZXMgb2YgdGhlIGdhbWUgd29ybGR3aWRlIHwgTnVtZXJpYyAocmF0aW8tc2NhbGVkKSAgICAgfCAgICAgCgoKIyBDbGFzcyBsYWJlbDoKClBvcHVsYXInIGlzIG91ciBjbGFzcyBsYWJlbCwgd2Ugd2lsbCB1c2UgR2xvYmFsX1NhbGVzIGF0dHJpYnV0ZSB0byBwcmVkaWN0IHdoZXRoZXIgYSBnYW1lIHdpbGwgc2VsbCAxMDAwMDAwIG9yIG1vcmUgZ2xvYmFsbHkuIE91ciB0YXNrIG9mIGRhdGEgbWluaW5nIGlzIHJlZ3Jlc3Npb24uCgoKCgoKCgoKCkltcG9ydGluZyBvdXIgZGF0YXNldDoKYGBge3J9CmRhdGFzZXQ9cmVhZC5jc3YoInZnc2FsZXMuY3N2IikKYGBgCgoKbG9hZGluZyBsaWJyYXJpZXMgbmVlZGVkIGZvciBvdXIgZGF0YSBtaW5pbmcgdGFza3M6CmBgYHtyfQpsaWJyYXJ5KG91dGxpZXJzKSAKbGlicmFyeShkcGx5cikKbGlicmFyeShIbWlzYykKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkobWxiZW5jaCkKbGlicmFyeShjYXJldCkKbGlicmFyeShmYXV4KQpsaWJyYXJ5KERhdGFFeHBsb3JlcikKbGlicmFyeShyYW5kb21Gb3Jlc3QpCm9wdGlvbnMobWF4LnByaW50PTk5OTk5OTkpCmBgYAoKCgoKR2VuZXJhbCBpbmZvIGFib3V0IG91ciBkYXRhc2V0IGluY2x1ZGluZyAgbnVtYmVyIG9mIHJvd3MgYW5kIGNvbHVtbnMsIGFuZCBjaGVraW5nIGRpbWVuc2lvbmFsaXR5IGFuZCBjb3VsdW1ucyBuYW1lczoKYGBge3J9Cm5yb3coZGF0YXNldCkKbmNvbChkYXRhc2V0KQpkaW0oZGF0YXNldCkKbmFtZXMoZGF0YXNldCkKYGBgCgoKCgpEYXRhc2V0IHN0cnVjdHVyZSBpbmNsdWRpbmcgbnVtYmVyIG9mIGNvdWx1bXMgYW5kIHJvd3MsIGF0dHJpYnV0ZSB0eXBlczoKYGBge3J9CnN0cihkYXRhc2V0KQpgYGAKCgoKc2FtcGxlIG9mIHJhdyBkYXRhc2V0KGZpcnN0IDEwIHJvd3MpOgpgYGB7cn0KaGVhZChkYXRhc2V0LCAxMCkKYGBgCgpzYW1wbGUgb2YgcmF3IGRhdGFzZXQobGFzdCAxMCByb3dzKToKYGBge3J9CnRhaWwoZGF0YXNldCwgMTApCmBgYAoKc3VtbWFyeSBvZiBvdXIgZGF0YXNldDoKYGBge3J9CnN1bW1hcnkoZGF0YXNldCkKYGBgCgp2YXJpYW5jZSBvZiBudW1lcmljIGRhdGE6CmBgYHtyfQp2YXIoZGF0YXNldCROQV9TYWxlcykKdmFyKGRhdGFzZXQkRVVfU2FsZXMpCnZhcihkYXRhc2V0JEpQX1NhbGVzKQp2YXIoZGF0YXNldCRPdGhlcl9TYWxlcykKdmFyKGRhdGFzZXQkR2xvYmFsX1NhbGVzKQpgYGAKCgoKCgoKIyBHcmFwaHM6CgpgYGB7cn0KZGF0YXNldDIgPC0gZGF0YXNldCAlPiUgc2FtcGxlX24oNTApCnRhYiA8LSBkYXRhc2V0MiRQbGF0Zm9ybSAlPiUgdGFibGUoKQpwcmVjZW50YWdlcyA8LSB0YWIgJT4lIHByb3AudGFibGUoKSAlPiUgcm91bmQoMykgKiAxMDAgCnR4dCA8LSBwYXN0ZTAobmFtZXModGFiKSwgJ1xuJywgcHJlY2VudGFnZXMsICclJykgCgpwaWUodGFiLCBsYWJlbHM9dHh0ICwgbWFpbiA9ICJQaWUgY2hhcnQgb2YgUGxhdGZvcm0iKSAKCmBgYAoKV2Ugbm90aWNlIGZyb20gdGhlIHBpZSBjaGFydCBvZiBwbGF0Zm9ybSBhdHRyaWJ1dGUgdGhhdCByZWxlYXNpbmcgYSBnYW1lIGZvciBQUyB1c2VycyB3aWxsIGluY3JlYXNlIHRoZSBwb3B1bGFyaXR5IG9mIHRoZSBnYW1lIHNpbmNlIGl0IGlzIHRoZSBtb3N0IGNvbW1vbiBwbGF0Zm9ybSBhbW9uZyBnYW1lcnMuIAoKCgoKCmBgYHtyfQojIGNvbG9yaW5nIGJhcnBsb3QgYW5kIGFkZGluZyB0ZXh0CnRhYjwtZGF0YXNldCRHZW5yZSAlPiUgdGFibGUoKSAKCnByZWNlbnRhZ2VzPC10YWIgJT4lIHByb3AudGFibGUoKSAlPiUgcm91bmQoMykqMTAwIAoKdHh0PC1wYXN0ZTAobmFtZXModGFiKSwgJ1xuJyxwcmVjZW50YWdlcywnJScpIAoKYmIgPC0gZGF0YXNldCRHZW5yZSAlPiUgdGFibGUoKSAlPiUgYmFycGxvdChheGlzbmFtZXM9RiwgbWFpbiA9ICJCYXJwbG90IGZvciBQb3B1bGFyIGdlbnJlcyAiLHlsYWI9J2NvdW50Jyxjb2w9YygncGluaycsJ2JsdWUnLCdsaWdodGJsdWUnLCdncmVlbicsJ2xpZ2h0Z3JlZW4nLCdyZWQnLCdvcmFuZ2UnLCdyZWQnLCdncmV5JywneWVsbG93JywnYXp1cmUnLCdvbGl2ZWRyYWInKSkgCgp0ZXh0KGJiLHRhYi8yLGxhYmVscz10eHQsY2V4PTEuNSkgCmBgYApJbiB0ZXJtcyBvZiBnZW5yZSwgYWN0aW9uIGdhbWVzIGFyZSB0aGUgbW9zdCBwb3B1bGFyLCBmb2xsb3dlZCBieSBzcG9ydHMgYW5kIG11c2ljIGdhbWVzLiBJdCBpcyBzYWZlIHRvIGFzc3VtZSB0aGF0IGEgaGlnaCBudW1iZXIgb2YgZ2VucmVzIG9mIHRoaXMgbmF0dXJlIGV4aXN0IGR1ZSB0byB0aGVpciBwb3B1bGFyaXR5IGFuZCBzYWxlcy4KCgoKCgpgYGB7cn0KYm94cGxvdChkYXRhc2V0JE5BX1NhbGVzICwgbWFpbj0iCkJveFBsb3QgZm9yIE5BX1NhbGVzIikKYGBgCgpgYGB7cn0KYm94cGxvdChkYXRhc2V0JEVVX1NhbGVzLCBtYWluPSIKIEJveFBsb3QgZm9yIEVVX1NhbGVzIikKYGBgCgpgYGB7cn0KYm94cGxvdChkYXRhc2V0JEpQX1NhbGVzICwgbWFpbj0iCiBCb3hQbG90IGZvciBKUF9TYWxlcyIpCmBgYAoKCgoKYGBge3J9CmJveHBsb3QoZGF0YXNldCRPdGhlcl9TYWxlcyAsIG1haW49IgogQm94UGxvdCBmb3IgT3RoZXJfU2FsZXMiKSAKYGBgICAKClRoZSBib3hwbG90IG9mIHRoZSBPdGhlci1zYWxlcyBhdHRyaWJ1dGUgaW5kaWNhdGUgdGhhdCB0aGUgdmFsdWVzIGFyZSBjbG9zZSB0byBlYWNoIG90aGVyICxhbmQgdGhlcmUgaXMgYSBsb3Qgb2Ygb3V0bGllcnMgc2luY2UgdGhlIGRhdGFzZXQgcmVwcmVzZW50cyB0aGUgZ2xvYmFsIHNhbGVzIG9mIHZpZGVvIGdhbWVzLiAKCgoKCmBgYHtyfQpib3hwbG90KGRhdGFzZXQkR2xvYmFsX1NhbGVzICwgbWFpbj0iQm94UGxvdCBmb3IgR2xvYmFsX1NhbGVzIikKCmBgYCAgClRoZSBib3hwbG90IG9mIHRoZSBHbG9iYWwtc2FsZXMgYXR0cmlidXRlIGluZGljYXRlIHRoYXQgdGhlIHZhbHVlcyBhcmUgY2xvc2UgdG8gZWFjaCBvdGhlciAsYW5kIHRoZXJlIGlzIGEgbG90IG9mIG91dGxpZXJzIHNpbmNlIHRoZSBkYXRhc2V0IHJlcHJlc2VudHMgdGhlIGdsb2JhbCBzYWxlcyBvZiB2aWRlbyBnYW1lcy4gCgoKCgpgYGB7cn0KcXBsb3QoZGF0YSA9IGRhdGFzZXQsIHg9R2xvYmFsX1NhbGVzLHk9R2VucmUsZmlsbD1JKCJ5ZWxsb3ciKSx3aWR0aD0wLjUgLGdlb20gPSAiYm94cGxvdCIgLCBtYWluID0gIkJveFBsb3RzIGZvciBnZW5yZSBhbmQgR2xvYmFsX1NhbGVzIikKYGBgCgpgYGB7cn0KZGF0YXNldCRZZWFyICU+JSB0YWJsZSgpICU+JSBiYXJwbG90KCBtYWluID0gIkJhcnBsb3QgZm9yIHllYXIiKQpgYGAKCmBgYHtyfQpwYWlycyh+TkFfU2FsZXMgKyBFVV9TYWxlcyArIEpQX1NhbGVzICsgT3RoZXJfU2FsZXMgKyBHbG9iYWxfU2FsZXMsIGRhdGEgPSBkYXRhc2V0LAogICAgICBtYWluID0gIlNhbGVzIFNjYXR0ZXJwbG90IikKYGBgICAgIApXZSB1c2VkIFNjYXR0ZXJwbG90IHRvIGRldGVybWluZSB0aGUgdHlwZSBvZiBjb3JyZWxhdGlvbiB3ZSBoYXZlIGJldHdlZW4gdGhlIHNhbGVzOyB3ZSBjYW4gc2VlIHRoYXQgdGhlIG1ham9yaXR5IGhhdmUgcG9zaXRpdmUgY29ycmVsYXRpb24gd2l0aCBlYWNoIG90aGVyLiAKIAogCiAgICAgIAojIFByZSAtIHByb2Nlc3NpbmcKCiMgVmFyYWlibGUgdHJhbnNmb3JtYXRpb24KYGBge3J9CmRhdGFzZXQkUmFuaz1hcy5jaGFyYWN0ZXIoZGF0YXNldCRSYW5rKQpgYGAKV2UgdHJhbnNmb3JtZWQgdGhlIFJhbmsgZnJvbSBudW1yaWMgdG8gY2hhcixiZWNhdXNlIHdlIHdpbGwgdXNlIHRoZW0gYXMgb3JkaW5hbCBkYXRhLgoKIyBOdWxsIGNoZWNraW5nCmBgYHtyfQpzdW0oaXMubmEoZGF0YXNldCRSYW5rKSkKTnVsbFJhbms8LWRhdGFzZXRbZGF0YXNldCRSYW5rPT0iTi9BIixdCk51bGxSYW5rCmBgYApjaGVja2luZyBmb3IgbnVsbHMgaW4gUmFuayAodGhlcmUgaXMgbm8gbnVsbHMpCmBgYHtyfQpzdW0oaXMubmEoZGF0YXNldCROYW1lKSkKTnVsbE5hbWU8LWRhdGFzZXRbZGF0YXNldCROYW1lPT0iTi9BIixdCk51bGxOYW1lCmBgYAoKY2hlY2tpbmcgZm9yIG51bGxzIGluIG5hbWUgKHRoZXJlIGlzIG5vIG51bGxzKQoKYGBge3J9CnN1bShpcy5uYShkYXRhc2V0JFBsYXRmb3JtKSkKTnVsbFBsYXRmb3JtPC1kYXRhc2V0W2RhdGFzZXQkUGxhdGZvcm09PSJOL0EiLF0KCgpgYGAKY2hlY2tpbmcgZm9yIG51bGxzIGluIFBsYXRmb3JtKHRoZXJlIGlzIG5vIG51bGxzKQoKYGBge3J9CnN1bShpcy5uYShkYXRhc2V0JFllYXIpKQpOdWxsWWVhcjwtZGF0YXNldFtkYXRhc2V0JFllYXI9PSJOL0EiLF0KTnVsbFllYXIKYGBgCmNoZWNraW5nIGZvciBudWxscyBpbiB5ZWFyCndlIHdvbid0IGRlbGV0ZSB0aGUgbnVsbCBhbmQgd2Ugd2lsbCBsZWF2ZSB0aGVtIGFzIGdsb2JhbCBjb25zdGFudCBiZWNhdXNlIHdlIHdhbnQgdGhlIHNhbGVzIGRhdGEgb3V0IG9mIHRoZW0uCgoKYGBge3J9CnN1bShpcy5uYShkYXRhc2V0JE90aGVyX1NhbGVzKSkKTnVsbE90aGVyX1NhbGVzPC1kYXRhc2V0W2RhdGFzZXQkT3RoZXJfU2FsZXM9PSJOL0EiLF0KCgpgYGAKVGhlcmUgaXMgbm8gbnVsbCB2YWx1ZXMgaW4gdGhlIG90aGVyX3NhbGVzLgoKYGBge3J9CnN1bShpcy5uYShkYXRhc2V0JEdlbnJlKSkKTnVsbEdlbnJlPC1kYXRhc2V0W2RhdGFzZXQkR2VucmU9PSJOL0EiLF0KTnVsbEdlbnJlCmBgYApjaGVja2luZyBmb3IgbnVsbHMgaW4gR2VucmUodGhlcmUgaXMgbm8gbnVsbHMpCmBgYHtyfQpzdW0oaXMubmEoZGF0YXNldCRQdWJsaXNoZXIpKQpOdWxsUHVibGlzaGVyPC1kYXRhc2V0W2RhdGFzZXQkUHVibGlzaGVyPT0iTi9BIixdCk51bGxQdWJsaXNoZXIKYGBgCmNoZWNraW5nIGZvciBudWxscyBpbiBQdWJsaXNoZXIuCndlIHdvbid0IGRlbGV0ZSB0aGUgbnVsbCBhbmQgd2Ugd2lsbCBsZWF2ZSB0aGVtIGFzIGdsb2JhbCBjb25zdGFudCBhcyBpdCBpcyBiZWNhdXNlIHdlIHdhbnQgdGhlIHNhbGVzIGRhdGEgb2YgdGhlbS4KCgpgYGB7cn0Kc3VtKGlzLm5hKGRhdGFzZXQkR2xvYmFsX1NhbGVzKSkKTnVsbEdsb2JhbF9TYWxlczwtZGF0YXNldFtkYXRhc2V0JEdsb2JhbF9TYWxlc3M9PSJOL0EiLF0KCgpgYGAKVGhlcmUgaXMgbm8gbnVsbCB2YWx1ZXMgaW4gdGhlIEdsb2JhbF9TYWxlcy4KCiMgRW5jb2RpbmcKYGBge3J9CmRhdGFzZXQkUGxhdGZvcm09ZmFjdG9yKGRhdGFzZXQkUGxhdGZvcm0sbGV2ZWxzPWMoIjI2MDAiLCIzRE8iLCIzRFMiLCJEQyIsIkRTIiwiR0IiLCJHQkEiLCJHQyIsIkdFTiIsIkdHIiwiTjY0IiwiTkVTIiwiTkciLCJQQyIsIlBDRlgiLCJQUyIsIlBTMiIsIlBTMyIsIlBTNCIsIlBTUCIsIlBTViIsIlNBVCIsIlNDRCIsIlNORVMiLCJURzE2IiwiV2lpIiwiV2lpVSIsIldTIiwiWDM2MCIsIlhCIiwiWE9uZSIpLCBsYWJlbHM9YygxLDIsMyw0LDUsNiw3LDgsOSwxMCwxMSwxMiwxMywxNCwxNSwxNiwxNywxOCwxOSwyMCwyMSwyMiwyMywyNCwyNSwyNiwyNywyOCwyOSwzMCwzMSkpCmBgYApTaW5jZSBtb3N0IG1hY2hpbmUgbGVhcm5pbmcgYWxnb3JpdGhtcyB3b3JrIHdpdGggbnVtYmVycyBhbmQgbm90IHdpdGggdGV4dCBvciBjYXRlZ29yaWNhbCB2YXJpYWJsZXMsIHRoaXMgY29sdW1uIHdpbGwgYmUgZW5jb2RlZCB0byBmYWNpbGl0YXRlIG91ciBkYXRhIG1pbmluZyB0YXNrLgoKYGBge3J9CmRhdGFzZXQkR2VucmU9ZmFjdG9yKGRhdGFzZXQkR2VucmUsbGV2ZWxzPWMoIkFjdGlvbiIsIkFkdmVudHVyZSIsIkZpZ2h0aW5nIiwiUGxhdGZvcm0iLCJQdXp6bGUiLCJSYWNpbmciLCJSb2xlLVBsYXlpbmciLCJTaG9vdGVyIiwiU2ltdWxhdGlvbiIsIlNwb3J0cyIsIlN0cmF0ZWd5IiwiTWlzYyIpLGxhYmVscz1jKDEsMiwzLDQsNSw2LDcsOCw5LDEwLDExLDEyKSkKYGBgClNpbmNlIG1vc3QgbWFjaGluZSBsZWFybmluZyBhbGdvcml0aG1zIHdvcmsgd2l0aCBudW1iZXJzIGFuZCBub3Qgd2l0aCB0ZXh0IG9yIGNhdGVnb3JpY2FsIHZhcmlhYmxlcywgdGhpcyBjb2x1bW4gd2lsbCBiZSBlbmNvZGVkIHRvIGZhY2lsaXRhdGUgb3VyIGRhdGEgbWluaW5nIHRhc2suCgojIE91dGxpZXJzCm91dGxpZXIgb2YgTkFfU2FsZXMKYGBge3J9Ck91dE5BX1NhbGVzID0gb3V0bGllcihkYXRhc2V0JE5BX1NhbGVzLCBsb2dpY2FsID1UUlVFKQpzdW0oT3V0TkFfU2FsZXMpCkZpbmRfb3V0bGllciA9IHdoaWNoKE91dE5BX1NhbGVzID09VFJVRSwgYXJyLmluZCA9IFRSVUUpCk91dE5BX1NhbGVzCkZpbmRfb3V0bGllcgpgYGAKb3V0bGllciBvZiBFVV9TYWxlcwpgYGB7cn0KT3V0RVVfU2FsZXMgPSBvdXRsaWVyKGRhdGFzZXQkRVVfU2FsZXMsIGxvZ2ljYWwgPVRSVUUpCnN1bShPdXRFVV9TYWxlcykKRmluZF9vdXRsaWVyID0gd2hpY2goT3V0RVVfU2FsZXMgPT1UUlVFLCBhcnIuaW5kID0gVFJVRSkKT3V0RVVfU2FsZXMKRmluZF9vdXRsaWVyCmBgYApvdXRsaWVyIG9mIEpQX1NhbGVzCmBgYHtyfQpPdXRKUF9TYWxlcyA9IG91dGxpZXIoZGF0YXNldCRKUF9TYWxlcywgbG9naWNhbCA9VFJVRSkKc3VtKE91dEpQX1NhbGVzKQpGaW5kX291dGxpZXIgPSB3aGljaChPdXRKUF9TYWxlcyA9PVRSVUUsIGFyci5pbmQgPSBUUlVFKQpPdXRKUF9TYWxlcwpGaW5kX291dGxpZXIKYGBgCgpvdXRsaWVyIG9mIG90aGVyX3NhbGVzIApgYGB7cn0KT3V0T1M9b3V0bGllcihkYXRhc2V0JE90aGVyX1NhbGVzLCBsb2dpY2FsPVRSVUUpICAKc3VtKE91dE9TKSAgCkZpbmRfb3V0bGllcj13aGljaChPdXRPUz09VFJVRSwgYXJyLmluZD1UUlVFKSAgCk91dE9TIApGaW5kX291dGxpZXIgCgpgYGAKCgpvdXRsaWVyIG9mIEdsb2JhbF9zYWxlcyAKCmBgYHtyfQpPdXRHUz1vdXRsaWVyKGRhdGFzZXQkR2xvYmFsX1NhbGVzLCBsb2dpY2FsPVRSVUUpICAKc3VtKE91dEdTKSAgCkZpbmRfb3V0bGllcj13aGljaChPdXRHUz09VFJVRSwgYXJyLmluZD1UUlVFKSAgCk91dEdTIApGaW5kX291dGxpZXIgCgpgYGAKCgoKIyBSZW1vdmUgb3V0bGllcnMgCmBgYHtyfQpkYXRhc2V0PSBkYXRhc2V0Wy1GaW5kX291dGxpZXIsXQpgYGAKCgoKIyBOb3JtYWxpemF0aW9uCkRhdGFzZXQgYmVmb3JlIG5vcm1hbGl6YXRpb246CmBgYHtyfQpkYXRzZXRXaXRob3V0Tm9ybWFsaXphdGlvbjwtZGF0YXNldApgYGAKCgpgYGB7cn0Kbm9ybWFsaXplIDwtIGZ1bmN0aW9uKHgpIHtyZXR1cm4gKCh4IC0gbWluKHgpKSAvIChtYXgoeCkgLSBtaW4oeCkpKX0KZGF0YXNldCROQV9TYWxlczwtbm9ybWFsaXplKGRhdHNldFdpdGhvdXROb3JtYWxpemF0aW9uJE5BX1NhbGVzKQpkYXRhc2V0JEVVX1NhbGVzPC1ub3JtYWxpemUoZGF0c2V0V2l0aG91dE5vcm1hbGl6YXRpb24kRVVfU2FsZXMpCmRhdGFzZXQkSlBfU2FsZXM8LW5vcm1hbGl6ZShkYXRzZXRXaXRob3V0Tm9ybWFsaXphdGlvbiRKUF9TYWxlcykKZGF0YXNldCRPdGhlcl9TYWxlczwtbm9ybWFsaXplKGRhdHNldFdpdGhvdXROb3JtYWxpemF0aW9uJE90aGVyX1NhbGVzKQpkYXRhc2V0JEdsb2JhbF9TYWxlczwtbm9ybWFsaXplKGRhdHNldFdpdGhvdXROb3JtYWxpemF0aW9uJEdsb2JhbF9TYWxlcykKYGBgCldlIGNob3NlIG1pbi1tYXggbm9ybWFsaXphdGlvbiBpbnN0ZWFkIG9mIHotc2NvcmUgbm9ybWFsaXphdGlvbiBiZWNhdXNlIG1pbi1tYXggdHJhbnNmb3JtIHRoZSBkYXRhIGludG8gYSBzcGVjaWZpYyByYW5nZSwgd2hpY2ggZW5oYW5jZXMgaXRzIHN1aXRhYmlsaXR5IGZvciB2aXN1YWxpemF0aW9uIGFuZCBjb21wYXJpc29uLiBBZGRpdGlvbmFsbHksIGl0IHNpbXBsaWZpZXMgdGhlIHByb2Nlc3Mgb2YgYXNzZXNzaW5nIGF0dHJpYnV0ZSBpbXBvcnRhbmNlIGFuZCB0aGVpciBjb250cmlidXRpb25zIHRvIHRoZSBtb2RlbC4KCgoKCgojIEZlYXV0cmUgc2VsZWN0aW9uCk91ciBjbGFzcyBsYWJlbCAocG9wdWxhcikgcmVmZXJzIHRvIEdsb2JhbF9TYWxlcy4gT3RoZXIgc2FsZXMgcmVnaW9ucyB3aWxsIGJlIGV2YWx1YXRlZCBiYXNlZCBvbiB0aGVpciBpbXBvcnRhbmNlIHRvIChnbG9iYWxfc2FsZXMpIGNvbHVtbi4gYW5kIHRob3NlIHRoYXQgYXJlIGxlc3MgaW1wb3J0YW50IHdpbGwgYmUgZGVsZXRlZCBmcm9tIHRoZSBkYXRhc2V0Lgp1c2Ugcm9jX2N1cnZlIGFyZWEgYXMgc2NvcmUKYGBge3J9CnJvY19pbXAgPC0gZmlsdGVyVmFySW1wKHggPSBkYXRhc2V0Wyw3OjEwXSwgeSA9IGRhdGFzZXQkR2xvYmFsX1NhbGVzKQpgYGAKc29ydCB0aGUgc2NvcmUgaW4gZGVjcmVhc2luZyBvcmRlcgpgYGB7cn0Kcm9jX2ltcCA8LSBkYXRhLmZyYW1lKGNiaW5kKHZhcmlhYmxlID0gcm93bmFtZXMocm9jX2ltcCksIHNjb3JlID0gcm9jX2ltcFssMV0pKQpyb2NfaW1wJHNjb3JlIDwtIGFzLmRvdWJsZShyb2NfaW1wJHNjb3JlKQpyb2NfaW1wW29yZGVyKHJvY19pbXAkc2NvcmUsZGVjcmVhc2luZyA9IFRSVUUpLF0KYGBgCndlIHdpbGwgcmVtb3ZlIHRoZSAoSlBfU2FsZXMpIGJlY2F1c2UgaXQgaXMgb2YgbG93IGltcG9ydGFuY2UgdG8gb3VyIGNsYXNzX2xhYmVsKEdsb2JhbF9TYWxlcykKYGBge3J9CmRhdGFzZXQ8LSBkYXRhc2V0WywtOV0KYGBgCgojIERhdGFzZXQgYWZ0ZXIgcHJlLXByb2Nlc3NpbmcKYGBge3J9CnByaW50KGRhdGFzZXQpCmBgYAoK
=======
LS0tDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KI0lUMzI2IFByb2plY3QNCg0KDQoNCg0KIyBEZXNjcmlwdGlvbiBvZiB0aGUgZGF0YXNldDoNCg0KVGhpcyBkYXRhc2V0LCBvYnRhaW5lZCBmcm9tIHZnY2hhcnR6LmNvbSwgcHJvdmlkZXMgYSB2YWx1YWJsZSByZXNvdXJjZSBmb3IgZXhwbG9yaW5nIHRoZSBkeW5hbWljcyBiZXR3ZWVuIGdhbWluZyBwbGF0Zm9ybXMgYW5kIGdlbnJlcyBpbiB0aGUgdG9wIDEwMCBnbG9iYWwgdmlkZW8gZ2FtZXMuIEl0IGVuYWJsZXMgdXMgdG8gYW5hbHl6ZSB0aGUgcGxhdGZvcm1zIHRoYXQgYXJlIGluZmx1ZW5jaW5nIHdvcmxkd2lkZSBzYWxlcywgaWRlbnRpZnkgdGhlIG1vc3QgcHJvc3Blcm91cyBnZW5yZXMgaW4gdmFyaW91cyBnbG9iYWwgcmVnaW9ucywgYW5kIHRyYWNrIHRoZSBldm9sdmluZyB0cmVuZHMgaW4gYm90aCBwbGF0Zm9ybSBwcmVmZXJlbmNlIGFuZCBnZW5yZSBwb3B1bGFyaXR5IG92ZXIgdGltZS4gDQoNCiMgU291cmNlIGFuZCBsaW5rOg0KU291cmNlOiBLYWdnbGUNCg0KVVJMIGxpbms6IGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvZ3JlZ29ydXQvdmlkZW9nYW1lc2FsZXMNCg0KIyBPdXIgZ29hbDoNCg0KT3VyIGdvYWwgIGZyb20gc3R1ZHlpbmcgdGhpcyBkYXRhc2V0IGlzIHRvIHV0aWxpemUgY2xhc3NpZmljYXRpb24gYW5kIGNsdXN0ZXJpbmcgdGVjaG5pcXVlcyBvbiB0aGUgaW5wdXQgZGF0YSB0byBtYWtlIHByZWRpY3Rpb25zIGFib3V0IHRoZSBwb3B1bGFyaXR5IG9mIHVwY29taW5nIGdhbWVzLg0KDQoNCg0KIyBBdHRyaWJ1dGVzIGRlc2NyaXB0aW9uOg0KDQoNCnwgKipBdHRyaWJ1dGVzIG5hbWUqKiB8ICoqRGVzY3JpcHRpb24qKiAgICAgICAgICAgICAgICAgICB8ICoqRGF0YSB0eXBlKiogfCANCnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLXwNCnxSYW5rICAgICAgICAgICAgICAgfCBSYW5raW5nIG9mIHRoZSBnYW1lIGJhc2VkIG9uIGdsb2JhbCBzYWxlcy4gfCBOdW1lcmljICAgICAgIHwNCnwgTmFtZSAgICAgICAgICAgIHwgTmFtZSBvZiB0aGUgZ2FtZS4gfCBOb21pbmFsICAgICAgIHwgDQp8IFBsYXRmb3JtICAgICAgfCBQbGF0Zm9ybSB0aGUgZ2FtZSB3YXMgcmVsZWFzZWQgb24uIHwgTm9taW5hbCAgICAgICB8IA0KfCBZZWFyICAgICAgICAgICAgICAgfCBZZWFyIHRoZSBnYW1lIHdhcyByZWxlYXNlZC4gfCBPcmRpbmFsICAgICAgIHwgDQp8IEdlbnJlICAgICAgICAgICAgfCBHZW5yZSBvZiB0aGUgZ2FtZSB8IE5vbWluYWwgICAgICAgfCANCnwgUHVibGlzaGVyICAgICAgfCBQdWJsaXNoZXIgb2YgdGhlIGdhbWUuIHwgTm9taW5hbCAgICAgICB8IA0KfCBOQV9TYWxlcyAgICAgIHwgU2FsZXMgb2YgdGhlIGdhbWUgaW4gTm9ydGggQW1lcmljYSB8IE51bWVyaWMgKHJhdGlvLXNjYWxlZCkgICAgICAgfCANCnwgRVVfU2FsZXMgICAgICAgfCBTYWxlcyBvZiB0aGUgZ2FtZSBpbiBFdXJvcGUgfCBOdW1lcmljIChyYXRpby1zY2FsZWQpICAgICAgICB8IA0KfCBKUF9TYWxlcyAgICAgICAgfCBTYWxlcyBvZiB0aGUgZ2FtZSBpbiBKYXBhbiB8IE51bWVyaWMgKHJhdGlvLXNjYWxlZCkgICAgICAgIHwgDQp8IE90aGVyX1NhbGVzIHwgU2FsZXMgb2YgdGhlIGdhbWUgaW4gb3RoZXIgcmVnaW9ucyB8IE51bWVyaWMgKHJhdGlvLXNjYWxlZCkgICAgICAgIHwgDQp8IEdsb2JhbF9TYWxlcyAgfCBUb3RhbCBzYWxlcyBvZiB0aGUgZ2FtZSB3b3JsZHdpZGUgfCBOdW1lcmljIChyYXRpby1zY2FsZWQpICAgICB8ICAgICANCg0KDQojIENsYXNzIGxhYmVsOg0KDQpQb3B1bGFyJyBpcyBvdXIgY2xhc3MgbGFiZWwsIHdlIHdpbGwgdXNlIEdsb2JhbF9TYWxlcyBhdHRyaWJ1dGUgdG8gcHJlZGljdCB3aGV0aGVyIGEgZ2FtZSB3aWxsIHNlbGwgMTAwMDAwMCBvciBtb3JlIGdsb2JhbGx5LiBPdXIgdGFzayBvZiBkYXRhIG1pbmluZyBpcyByZWdyZXNzaW9uLg0KDQoNCg0KDQpgYGB7cn0NCmRhdGFzZXQ9cmVhZC5jc3YoInZnc2FsZXMuY3N2IikNCmBgYA0KSW1wb3J0aW5nIG91ciBkYXRhc2V0Lg0KDQoNCmBgYHtyfQ0KbGlicmFyeShvdXRsaWVycykgDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShIbWlzYykNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoY293cGxvdCkNCmxpYnJhcnkobWxiZW5jaCkNCmxpYnJhcnkoY2FyZXQpDQpsaWJyYXJ5KGZhdXgpDQpsaWJyYXJ5KERhdGFFeHBsb3JlcikNCmxpYnJhcnkocmFuZG9tRm9yZXN0KQ0Kb3B0aW9ucyhtYXgucHJpbnQ9OTk5OTk5OSkNCmBgYA0KDQpsb2FkaW5nIGxpYnJhcmllcyBuZWVkZWQgZm9yIG91ciBkYXRhIG1pbmluZyB0YXNrcy4NCg0KDQpgYGB7cn0NCm5yb3coZGF0YXNldCkNCm5jb2woZGF0YXNldCkNCmRpbShkYXRhc2V0KQ0KbmFtZXMoZGF0YXNldCkNCmBgYA0KR2VuZXJhbCBpbmZvIGFib3V0IG91ciBkYXRhc2V0IGluY2x1ZGluZyAgbnVtYmVyIG9mIHJvd3MgYW5kIGNvbHVtbnMsIGFuZCBjaGVraW5nIGRpbWVuc2lvbmFsaXR5IGFuZCBjb3VsdW1ucyBuYW1lcy4NCg0KYGBge3J9DQpzdHIoZGF0YXNldCkNCmBgYA0KRGF0YXNldCBzdHJ1Y3R1cmUgaW5jbHVkaW5nIG51bWJlciBvZiBjb3VsdW1zIGFuZCByb3dzLCBhdHRyaWJ1dGUgdHlwZXMuIA0KDQpgYGB7cn0NCmhlYWQoZGF0YXNldCwgMTApDQpgYGANCnNhbXBsZSBvZiByYXcgZGF0YXNldChmaXJzdCAxMCByb3dzKS4NCg0KYGBge3J9DQp0YWlsKGRhdGFzZXQsIDEwKQ0KYGBgDQpzYW1wbGUgb2YgcmF3IGRhdGFzZXQobGFzdCAxMCByb3dzKS4NCg0KYGBge3J9DQpzdW1tYXJ5KGRhdGFzZXQpDQpgYGANCnN1bW1hcnkgb2Ygb3VyIGRhdGFzZXQuDQoNCmBgYHtyfQ0KdmFyKGRhdGFzZXQkTkFfU2FsZXMpDQp2YXIoZGF0YXNldCRFVV9TYWxlcykNCnZhcihkYXRhc2V0JEpQX1NhbGVzKQ0KdmFyKGRhdGFzZXQkT3RoZXJfU2FsZXMpDQp2YXIoZGF0YXNldCRHbG9iYWxfU2FsZXMpDQpgYGANCnZhcmlhbmNlIG9mIG51bWVyaWMgZGF0YQ0KDQojIEdyYXBoczoNCg0KYGBge3J9DQpkYXRhc2V0MiA8LSBkYXRhc2V0ICU+JSBzYW1wbGVfbig1MCkNCnRhYiA8LSBkYXRhc2V0MiRQbGF0Zm9ybSAlPiUgdGFibGUoKQ0KcHJlY2VudGFnZXMgPC0gdGFiICU+JSBwcm9wLnRhYmxlKCkgJT4lIHJvdW5kKDMpICogMTAwIA0KdHh0IDwtIHBhc3RlMChuYW1lcyh0YWIpLCAnXG4nLCBwcmVjZW50YWdlcywgJyUnKSANCg0KcGllKHRhYiwgbGFiZWxzPXR4dCAsIG1haW4gPSAiUGllIGNoYXJ0IG9mIFBsYXRmb3JtIikgDQoNCmBgYA0KDQpXZSBub3RpY2UgZnJvbSB0aGUgcGllIGNoYXJ0IG9mIHBsYXRmb3JtIGF0dHJpYnV0ZSB0aGF0IHJlbGVhc2luZyBhIGdhbWUgZm9yIFBTIHVzZXJzIHdpbGwgaW5jcmVhc2UgdGhlIHBvcHVsYXJpdHkgb2YgdGhlIGdhbWUgc2luY2UgaXQgaXMgdGhlIG1vc3QgY29tbW9uIHBsYXRmb3JtIGFtb25nIGdhbWVycy4gDQoNCg0KDQoNCg0KYGBge3J9DQojIGNvbG9yaW5nIGJhcnBsb3QgYW5kIGFkZGluZyB0ZXh0DQp0YWI8LWRhdGFzZXQkR2VucmUgJT4lIHRhYmxlKCkgDQoNCnByZWNlbnRhZ2VzPC10YWIgJT4lIHByb3AudGFibGUoKSAlPiUgcm91bmQoMykqMTAwIA0KDQp0eHQ8LXBhc3RlMChuYW1lcyh0YWIpLCAnXG4nLHByZWNlbnRhZ2VzLCclJykgDQoNCmJiIDwtIGRhdGFzZXQkR2VucmUgJT4lIHRhYmxlKCkgJT4lIGJhcnBsb3QoYXhpc25hbWVzPUYsIG1haW4gPSAiQmFycGxvdCBmb3IgUG9wdWxhciBnZW5yZXMgIix5bGFiPSdjb3VudCcsY29sPWMoJ3BpbmsnLCdibHVlJywnbGlnaHRibHVlJywnZ3JlZW4nLCdsaWdodGdyZWVuJywncmVkJywnb3JhbmdlJywncmVkJywnZ3JleScsJ3llbGxvdycsJ2F6dXJlJywnb2xpdmVkcmFiJykpIA0KDQp0ZXh0KGJiLHRhYi8yLGxhYmVscz10eHQsY2V4PTEuNSkgDQpgYGANCkluIHRlcm1zIG9mIGdlbnJlLCBhY3Rpb24gZ2FtZXMgYXJlIHRoZSBtb3N0IHBvcHVsYXIsIGZvbGxvd2VkIGJ5IHNwb3J0cyBhbmQgbXVzaWMgZ2FtZXMuIEl0IGlzIHNhZmUgdG8gYXNzdW1lIHRoYXQgYSBoaWdoIG51bWJlciBvZiBnZW5yZXMgb2YgdGhpcyBuYXR1cmUgZXhpc3QgZHVlIHRvIHRoZWlyIHBvcHVsYXJpdHkgYW5kIHNhbGVzLg0KDQoNCmBgYHtyfQ0KYm94cGxvdChkYXRhc2V0JE5BX1NhbGVzICwgbWFpbj0iDQpCb3hQbG90IGZvciBOQV9TYWxlcyIpDQpgYGANCg0KYGBge3J9DQpib3hwbG90KGRhdGFzZXQkRVVfU2FsZXMsIG1haW49Ig0KIEJveFBsb3QgZm9yIEVVX1NhbGVzIikNCmBgYA0KDQpgYGB7cn0NCmJveHBsb3QoZGF0YXNldCRKUF9TYWxlcyAsIG1haW49Ig0KIEJveFBsb3QgZm9yIEpQX1NhbGVzIikNCmBgYA0KDQoNCg0KDQpgYGB7cn0NCmJveHBsb3QoZGF0YXNldCRPdGhlcl9TYWxlcyAsIG1haW49Ig0KIEJveFBsb3QgZm9yIE90aGVyX1NhbGVzIikgDQpgYGAgIA0KDQpUaGUgYm94cGxvdCBvZiB0aGUgT3RoZXItc2FsZXMgYXR0cmlidXRlIGluZGljYXRlIHRoYXQgdGhlIHZhbHVlcyBhcmUgY2xvc2UgdG8gZWFjaCBvdGhlciAsYW5kIHRoZXJlIGlzIGEgbG90IG9mIG91dGxpZXJzIHNpbmNlIHRoZSBkYXRhc2V0IHJlcHJlc2VudHMgdGhlIGdsb2JhbCBzYWxlcyBvZiB2aWRlbyBnYW1lcy4gDQoNCg0KDQoNCmBgYHtyfQ0KYm94cGxvdChkYXRhc2V0JEdsb2JhbF9TYWxlcyAsIG1haW49IkJveFBsb3QgZm9yIEdsb2JhbF9TYWxlcyIpDQoNCmBgYCAgDQpUaGUgYm94cGxvdCBvZiB0aGUgR2xvYmFsLXNhbGVzIGF0dHJpYnV0ZSBpbmRpY2F0ZSB0aGF0IHRoZSB2YWx1ZXMgYXJlIGNsb3NlIHRvIGVhY2ggb3RoZXIgLGFuZCB0aGVyZSBpcyBhIGxvdCBvZiBvdXRsaWVycyBzaW5jZSB0aGUgZGF0YXNldCByZXByZXNlbnRzIHRoZSBnbG9iYWwgc2FsZXMgb2YgdmlkZW8gZ2FtZXMuIA0KDQoNCg0KDQpgYGB7cn0NCnFwbG90KGRhdGEgPSBkYXRhc2V0LCB4PUdsb2JhbF9TYWxlcyx5PUdlbnJlLGZpbGw9SSgieWVsbG93Iiksd2lkdGg9MC41ICxnZW9tID0gImJveHBsb3QiICwgbWFpbiA9ICJCb3hQbG90cyBmb3IgZ2VucmUgYW5kIEdsb2JhbF9TYWxlcyIpDQpgYGANCg0KYGBge3J9DQpkYXRhc2V0JFllYXIgJT4lIHRhYmxlKCkgJT4lIGJhcnBsb3QoIG1haW4gPSAiQmFycGxvdCBmb3IgeWVhciIpDQpgYGANCg0KYGBge3J9DQpwYWlycyh+TkFfU2FsZXMgKyBFVV9TYWxlcyArIEpQX1NhbGVzICsgT3RoZXJfU2FsZXMgKyBHbG9iYWxfU2FsZXMsIGRhdGEgPSBkYXRhc2V0LA0KICAgICAgbWFpbiA9ICJTYWxlcyBTY2F0dGVycGxvdCIpDQpgYGAgICAgDQpXZSB1c2VkIFNjYXR0ZXJwbG90IHRvIGRldGVybWluZSB0aGUgdHlwZSBvZiBjb3JyZWxhdGlvbiB3ZSBoYXZlIGJldHdlZW4gdGhlIHNhbGVzOyB3ZSBjYW4gc2VlIHRoYXQgdGhlIG1ham9yaXR5IGhhdmUgcG9zaXRpdmUgY29ycmVsYXRpb24gd2l0aCBlYWNoIG90aGVyLiANCiANCiANCiAgICAgIA0KIyBQcmUgLSBwcm9jZXNzaW5nDQoNCiMgVmFyYWlibGUgdHJhbnNmb3JtYXRpb24NCmBgYHtyfQ0KZGF0YXNldCRSYW5rPWFzLmNoYXJhY3RlcihkYXRhc2V0JFJhbmspDQpgYGANClJhbmsgc2hvdWxkIGJlIGNoYXIgYW5kIG5vdCBudW1lcmljLGJlY2F1c2Ugd2Ugd2lsbCB1c2UgdGhlbSBhcyBvcmRpbmFsIGRhdGEuDQoNCiMgTnVsbCBjaGVja2luZw0KYGBge3J9DQpzdW0oaXMubmEoZGF0YXNldCRSYW5rKSkNCk51bGxSYW5rPC1kYXRhc2V0W2RhdGFzZXQkUmFuaz09Ik4vQSIsXQ0KTnVsbFJhbmsNCmBgYA0KY2hlY2tpbmcgZm9yIG51bGxzIGluIFJhbmsgKHRoZXJlIGlzIG5vIG51bGxzKQ0KYGBge3J9DQpzdW0oaXMubmEoZGF0YXNldCROYW1lKSkNCk51bGxOYW1lPC1kYXRhc2V0W2RhdGFzZXQkTmFtZT09Ik4vQSIsXQ0KTnVsbE5hbWUNCmBgYA0KDQpjaGVja2luZyBmb3IgbnVsbHMgaW4gbmFtZSAodGhlcmUgaXMgbm8gbnVsbHMpDQoNCmBgYHtyfQ0Kc3VtKGlzLm5hKGRhdGFzZXQkUGxhdGZvcm0pKQ0KTnVsbFBsYXRmb3JtPC1kYXRhc2V0W2RhdGFzZXQkUGxhdGZvcm09PSJOL0EiLF0NCg0KDQpgYGANCmNoZWNraW5nIGZvciBudWxscyBpbiBQbGF0Zm9ybSh0aGVyZSBpcyBubyBudWxscykNCg0KYGBge3J9DQpzdW0oaXMubmEoZGF0YXNldCRZZWFyKSkNCk51bGxZZWFyPC1kYXRhc2V0W2RhdGFzZXQkWWVhcj09Ik4vQSIsXQ0KTnVsbFllYXINCmBgYA0KY2hlY2tpbmcgZm9yIG51bGxzIGluIHllYXINCndlIHdvbid0IGRlbGV0ZSB0aGUgbnVsbCBhbmQgd2Ugd2lsbCBsZWF2ZSB0aGVtIGFzIGdsb2JhbCBjb25zdGFudCBhcyBpdCBpcyBiZWNhdXNlIHdlIHdhbnQgdGhlIHNhbGVzIGRhdGEgb2YgdGhlbS4NCg0KYGBge3J9DQpzdW0oaXMubmEoZGF0YXNldCRHZW5yZSkpDQpOdWxsR2VucmU8LWRhdGFzZXRbZGF0YXNldCRHZW5yZT09Ik4vQSIsXQ0KTnVsbEdlbnJlDQpgYGANCmNoZWNraW5nIGZvciBudWxscyBpbiBHZW5yZSh0aGVyZSBpcyBubyBudWxscykNCg0KYGBge3J9DQpzdW0oaXMubmEoZGF0YXNldCRQdWJsaXNoZXIpKQ0KTnVsbFB1Ymxpc2hlcjwtZGF0YXNldFtkYXRhc2V0JFB1Ymxpc2hlcj09Ik4vQSIsXQ0KTnVsbFB1Ymxpc2hlcg0KYGBgDQpjaGVja2luZyBmb3IgbnVsbHMgaW4gUHVibGlzaGVyLg0Kd2Ugd29uJ3QgZGVsZXRlIHRoZSBudWxsIGFuZCB3ZSB3aWxsIGxlYXZlIHRoZW0gYXMgZ2xvYmFsIGNvbnN0YW50IGFzIGl0IGlzIGJlY2F1c2Ugd2Ugd2FudCB0aGUgc2FsZXMgZGF0YSBvZiB0aGVtLg0KDQpgYGB7cn0NCnN1bShpcy5uYShkYXRhc2V0JE90aGVyX1NhbGVzKSkNCk51bGxPdGhlcl9TYWxlczwtZGF0YXNldFtkYXRhc2V0JE90aGVyX1NhbGVzPT0iTi9BIixdDQoNCg0KYGBgDQpUaGVyZSBpcyBubyBudWxsIHZhbHVlcyBpbiB0aGUgb3RoZXJfc2FsZXMuDQoNCmBgYHtyfQ0Kc3VtKGlzLm5hKGRhdGFzZXQkR2xvYmFsX1NhbGVzKSkNCk51bGxHbG9iYWxfU2FsZXM8LWRhdGFzZXRbZGF0YXNldCRHbG9iYWxfU2FsZXNzPT0iTi9BIixdDQoNCg0KYGBgDQpUaGVyZSBpcyBubyBudWxsIHZhbHVlcyBpbiB0aGUgR2xvYmFsX1NhbGVzLg0KDQojIEVuY29kaW5nDQpgYGB7cn0NCmRhdGFzZXQkUGxhdGZvcm09ZmFjdG9yKGRhdGFzZXQkUGxhdGZvcm0sbGV2ZWxzPWMoIjI2MDAiLCIzRE8iLCIzRFMiLCJEQyIsIkRTIiwiR0IiLCJHQkEiLCJHQyIsIkdFTiIsIkdHIiwiTjY0IiwiTkVTIiwiTkciLCJQQyIsIlBDRlgiLCJQUyIsIlBTMiIsIlBTMyIsIlBTNCIsIlBTUCIsIlBTViIsIlNBVCIsIlNDRCIsIlNORVMiLCJURzE2IiwiV2lpIiwiV2lpVSIsIldTIiwiWDM2MCIsIlhCIiwiWE9uZSIpLCBsYWJlbHM9YygxLDIsMyw0LDUsNiw3LDgsOSwxMCwxMSwxMiwxMywxNCwxNSwxNiwxNywxOCwxOSwyMCwyMSwyMiwyMywyNCwyNSwyNiwyNywyOCwyOSwzMCwzMSkpDQpgYGANClNpbmNlIG1vc3QgbWFjaGluZSBsZWFybmluZyBhbGdvcml0aG1zIHdvcmsgd2l0aCBudW1iZXJzIGFuZCBub3Qgd2l0aCB0ZXh0IG9yIGNhdGVnb3JpY2FsIHZhcmlhYmxlcywgdGhpcyBjb2x1bW4gd2lsbCBiZSBlbmNvZGVkLg0KDQpgYGB7cn0NCmRhdGFzZXQkR2VucmU9ZmFjdG9yKGRhdGFzZXQkR2VucmUsbGV2ZWxzPWMoIkFjdGlvbiIsIkFkdmVudHVyZSIsIkZpZ2h0aW5nIiwiUGxhdGZvcm0iLCJQdXp6bGUiLCJSYWNpbmciLCJSb2xlLVBsYXlpbmciLCJTaG9vdGVyIiwiU2ltdWxhdGlvbiIsIlNwb3J0cyIsIlN0cmF0ZWd5IiwiTWlzYyIpLGxhYmVscz1jKDEsMiwzLDQsNSw2LDcsOCw5LDEwLDExLDEyKSkNCmBgYA0KU2luY2UgbW9zdCBtYWNoaW5lIGxlYXJuaW5nIGFsZ29yaXRobXMgd29yayB3aXRoIG51bWJlcnMgYW5kIG5vdCB3aXRoIHRleHQgb3IgY2F0ZWdvcmljYWwgdmFyaWFibGVzLCB0aGlzIGNvbHVtbiB3aWxsIGJlIGVuY29kZWQuDQoNCg0KIyBPdXRsaWVycw0Kb3V0bGllciBvZiBOQV9TYWxlcw0KYGBge3J9DQpPdXROQV9TYWxlcyA9IG91dGxpZXIoZGF0YXNldCROQV9TYWxlcywgbG9naWNhbCA9VFJVRSkNCnN1bShPdXROQV9TYWxlcykNCkZpbmRfb3V0bGllciA9IHdoaWNoKE91dE5BX1NhbGVzID09VFJVRSwgYXJyLmluZCA9IFRSVUUpDQpPdXROQV9TYWxlcw0KRmluZF9vdXRsaWVyDQpgYGANCm91dGxpZXIgb2YgRVVfU2FsZXMNCmBgYHtyfQ0KT3V0RVVfU2FsZXMgPSBvdXRsaWVyKGRhdGFzZXQkRVVfU2FsZXMsIGxvZ2ljYWwgPVRSVUUpDQpzdW0oT3V0RVVfU2FsZXMpDQpGaW5kX291dGxpZXIgPSB3aGljaChPdXRFVV9TYWxlcyA9PVRSVUUsIGFyci5pbmQgPSBUUlVFKQ0KT3V0RVVfU2FsZXMNCkZpbmRfb3V0bGllcg0KYGBgDQpvdXRsaWVyIG9mIEpQX1NhbGVzDQpgYGB7cn0NCk91dEpQX1NhbGVzID0gb3V0bGllcihkYXRhc2V0JEpQX1NhbGVzLCBsb2dpY2FsID1UUlVFKQ0Kc3VtKE91dEpQX1NhbGVzKQ0KRmluZF9vdXRsaWVyID0gd2hpY2goT3V0SlBfU2FsZXMgPT1UUlVFLCBhcnIuaW5kID0gVFJVRSkNCk91dEpQX1NhbGVzDQpGaW5kX291dGxpZXINCmBgYA0KDQpvdXRsaWVyIG9mIG90aGVyX3NhbGVzIA0KYGBge3J9DQpPdXRPUz1vdXRsaWVyKGRhdGFzZXQkT3RoZXJfU2FsZXMsIGxvZ2ljYWw9VFJVRSkgIA0Kc3VtKE91dE9TKSAgDQpGaW5kX291dGxpZXI9d2hpY2goT3V0T1M9PVRSVUUsIGFyci5pbmQ9VFJVRSkgIA0KT3V0T1MgDQpGaW5kX291dGxpZXIgDQoNCmBgYA0KDQoNCm91dGxpZXIgb2YgR2xvYmFsX3NhbGVzIA0KDQpgYGB7cn0NCk91dEdTPW91dGxpZXIoZGF0YXNldCRHbG9iYWxfU2FsZXMsIGxvZ2ljYWw9VFJVRSkgIA0Kc3VtKE91dEdTKSAgDQpGaW5kX291dGxpZXI9d2hpY2goT3V0R1M9PVRSVUUsIGFyci5pbmQ9VFJVRSkgIA0KT3V0R1MgDQpGaW5kX291dGxpZXIgDQoNCmBgYA0KDQoNCg0KIyBSZW1vdmUgb3V0bGllcnMgDQpgYGB7cn0NCmRhdGFzZXQ9IGRhdGFzZXRbLUZpbmRfb3V0bGllcixdDQpgYGANCg0KDQoNCiMgTm9ybWFsaXphdGlvbg0KDQpgYGB7cn0NCmRhdHNldFdpdGhvdXROb3JtYWxpemF0aW9uPC1kYXRhc2V0DQpgYGANCmRhdGFzZXQgYmVmb3JlIG5vcm1hbGl6YXRpb24NCg0KYGBge3J9DQpub3JtYWxpemUgPC0gZnVuY3Rpb24oeCkge3JldHVybiAoKHggLSBtaW4oeCkpIC8gKG1heCh4KSAtIG1pbih4KSkpfQ0KZGF0YXNldCROQV9TYWxlczwtbm9ybWFsaXplKGRhdHNldFdpdGhvdXROb3JtYWxpemF0aW9uJE5BX1NhbGVzKQ0KZGF0YXNldCRFVV9TYWxlczwtbm9ybWFsaXplKGRhdHNldFdpdGhvdXROb3JtYWxpemF0aW9uJEVVX1NhbGVzKQ0KZGF0YXNldCRKUF9TYWxlczwtbm9ybWFsaXplKGRhdHNldFdpdGhvdXROb3JtYWxpemF0aW9uJEpQX1NhbGVzKQ0KZGF0YXNldCRPdGhlcl9TYWxlczwtbm9ybWFsaXplKGRhdHNldFdpdGhvdXROb3JtYWxpemF0aW9uJE90aGVyX1NhbGVzKQ0KZGF0YXNldCRHbG9iYWxfU2FsZXM8LW5vcm1hbGl6ZShkYXRzZXRXaXRob3V0Tm9ybWFsaXphdGlvbiRHbG9iYWxfU2FsZXMpDQpgYGANCm1pbi1tYXggbm9ybWFsaXphdGlvbg0Kd2Ugd2lsbCB1c2UgdGhlIG1pbi1tYXggbm9ybWFsaXphdGlvbjsgaXQncyBiZXR0ZXIgZm9yIHZpc3VhbGl6YXRpb24uDQoNCg0KIyBGZWF1dHJlIHNlbGVjdGlvbg0KT3VyIGNsYXNzIGxhYmVsIChwb3B1bGFyKSByZWZlcnMgdG8gR2xvYmFsX1NhbGVzLiBPdGhlciBzYWxlcyByZWdpb25zIHdpbGwgYmUgZXZhbHVhdGVkIGJhc2VkIG9uIHRoZWlyIGltcG9ydGFuY2UgdG8gKGdsb2JhbF9zYWxlcykgY29sdW1uLiBhbmQgdGhvc2UgdGhhdCBhcmUgbGVzcyBpbXBvcnRhbnQgd2lsbCBiZSBkZWxldGVkIGZyb20gdGhlIGRhdGFzZXQuDQp1c2Ugcm9jX2N1cnZlIGFyZWEgYXMgc2NvcmUNCmBgYHtyfQ0Kcm9jX2ltcCA8LSBmaWx0ZXJWYXJJbXAoeCA9IGRhdGFzZXRbLDc6MTBdLCB5ID0gZGF0YXNldCRHbG9iYWxfU2FsZXMpDQpgYGANCnNvcnQgdGhlIHNjb3JlIGluIGRlY3JlYXNpbmcgb3JkZXINCmBgYHtyfQ0Kcm9jX2ltcCA8LSBkYXRhLmZyYW1lKGNiaW5kKHZhcmlhYmxlID0gcm93bmFtZXMocm9jX2ltcCksIHNjb3JlID0gcm9jX2ltcFssMV0pKQ0Kcm9jX2ltcCRzY29yZSA8LSBhcy5kb3VibGUocm9jX2ltcCRzY29yZSkNCnJvY19pbXBbb3JkZXIocm9jX2ltcCRzY29yZSxkZWNyZWFzaW5nID0gVFJVRSksXQ0KYGBgDQp3ZSB3aWxsIHJtb3ZlIHRoZSAoSlBfU2FsZXMpIGJlY2F1c2UgaXQgaXMgb2YgbG93IGltcG9ydGFuY2UgdG8gb3VyIGNsYXNzX2xhYmVsKEdsb2JhbF9TYWxlcykNCmBgYHtyfQ0KZGF0YXNldDwtIGRhdGFzZXRbLC05XQ0KYGBgDQoNCiMgRGF0YXNldCBhZnRlciBwcmUtcHJvY2Vzc2luZw0KYGBge3J9DQpwcmludChkYXRhc2V0KQ0KYGBgDQoNCg==
>>>>>>> 0a8dbb82ad1438b1cf018ebed6baaf49963f803f